#include <assert.h>
#include "evaluation.h"

evaluation::evaluation(const std::vector<expression> &exprs)
{
    for (const auto &test : exprs) {
        exprs_store.insert(std::make_pair(test.expr_id_temp, test));
    }
}

void evaluation::add_kwargs_double(
    const char *key,
    double value)
{
    args_[key] = test(value);
}

void evaluation::add_kwargs_ndarray(
    const char *key,
    int dim,
    size_t shape[],
    double data[])
{
    args_[key] = test(dim, shape, data);
}

int evaluation::execute()
{
    std::map<std::string, test>::iterator evp_weight;
    std::map<std::string, test>::iterator evp_bias;

    std::map<std::string, int>::iterator evp_kernel_size;
    std::map<std::string, int>::iterator evp_stride;
    std::map<std::string, int>::iterator pos_i;
    std::map<std::string, int>::iterator pos_o;    

    if (exprs_store.empty()) {
        printf("err:%d %p:\n", __LINE__, this);
        return -1;
    }

    for (auto &n : exprs_store) {
        auto &p = n.second;

        switch (p.op_type_temp[0]) {
            case 'I':
                if(p.op_type_temp.length() == 5){
                    p.temp = args_[p.op_name_temp];
                }else{
                    p.temp = Inut2d(args_[p.op_name_temp]);
                }
                break;

            case 'A':
                p.temp = exprs_store.find(p.inputs_temp[0])->second.temp + exprs_store.find(p.inputs_temp[1])->second.temp;
                break;

            case 'S':
                p.temp = exprs_store.find(p.inputs_temp[0])->second.temp - exprs_store.find(p.inputs_temp[1])->second.temp;
                break;

            case 'M':
                if(p.op_type_temp.length() == 3){
                    p.temp = exprs_store.find(p.inputs_temp[0])->second.temp   *   exprs_store.find(p.inputs_temp[1])->second.temp;
                }else{
                    evp_kernel_size = p.exp_ker_str.find("kernel_size");
                    evp_stride = p.exp_ker_str.find("stride");
                    p.temp = MaxPool2d(exprs_store.find(p.inputs_temp[0])->second.temp,(*evp_kernel_size).second,(*evp_stride).second );
                }
                break;

            case 'R':
                p.temp = ReLU(exprs_store.find(p.inputs_temp[0])->second.temp);
                break;

            case 'F':
                p.temp = Flatten(exprs_store.find(p.inputs_temp[0])->second.temp);
                break;

            case 'L':
                evp_weight = p.exp_value.find("weight");
                evp_bias = p.exp_value.find("bias");
                p.temp = Linear((*evp_weight).second, exprs_store.find(p.inputs_temp[0])->second.temp, (*evp_bias).second);
                break;

            case 'C':
                evp_weight = p.exp_value.find("weight");
                evp_bias = p.exp_value.find("bias");
                evp_kernel_size = p.exp_ker_str.find("kernel_size");
                pos_i = p.exp_ker_str.find("in_channels");
                pos_o = p.exp_ker_str.find("out_channels");
                p.temp = Conv2d(exprs_store.find(p.inputs_temp[0])->second.temp,
                             (*pos_i).second,
                             (*pos_o).second,
                             (*evp_kernel_size).second,
                             (*evp_weight).second,
                             (*evp_bias).second
                             );
                break; 
                
            default:
                break;
        }
    }

  return 0;
}

test &evaluation::get_result() {
    return exprs_store.rbegin()->second.temp;
}